package com.easy.lab.shixun.service.manager;

import com.easy.lab.shixun.api.bo.response.TokenInfoResponse;
import com.easy.lab.shixun.common.base.BaseError;
import com.easy.lab.shixun.common.base.BaseException;
import io.openvidu.java.client.OpenVidu;
import io.openvidu.java.client.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketSession;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author: https://gitee.com/wesleyOne
 * @Date: 12.12 2019
 */
@Configuration
@Slf4j
public class SimpleCoreManager {

    /**
     * 缓存用户登入信息
     */
    private static final Map<String, TokenInfoResponse> TOKEN_INFO = new ConcurrentHashMap<>(128);
    /**
     * 缓存WS会话
     */
    private static final Map<String, WebSocketSession> WEBSOCKET_SESSIONS = new ConcurrentHashMap<>(128);
    /**
     * 缓存群-成员token信息
     */
    private static final Map<String, List<String>> GROUP_REF_MEMBER = new ConcurrentHashMap<>(16);
    /**
     * 缓存群-openvidu会话
     */
    private static final Map<String, Session> OPENVIDU_SESSIONS = new ConcurrentHashMap<>(16);
    /**
     * 缓存-openvidu录像id
     */
    private static final Map<String, String> OPENVIDU_RECORDINGS = new ConcurrentHashMap<>(16);

    @Bean
    public OpenVidu openVidu(@Value("${openvidu.secret}") String secret, @Value("${openvidu.url}") String openviduUrl) {
        return new OpenVidu(openviduUrl, secret);
    }

    public Map<String, TokenInfoResponse> getReadOnlyTokenInfo() {
        return Collections.unmodifiableMap(TOKEN_INFO);
    }

    public Map<String, List<String>> getReadOnlyGroupRefMember() {
        return Collections.unmodifiableMap(GROUP_REF_MEMBER);
    }

    public Map<String, Session> getOpenviduSessions() {
        return Collections.unmodifiableMap(OPENVIDU_SESSIONS);
    }

    public Map<String, String> getOpenviduRecordings() {
        return Collections.unmodifiableMap(OPENVIDU_RECORDINGS);
    }

    /**
     * 添加用户登录信息
     * @param token
     * @param tokenInfoResponse
     */
    public void addTokenInfo(String token, TokenInfoResponse tokenInfoResponse) {
        TOKEN_INFO.put(token, tokenInfoResponse);
    }

    /**
     * 设置ws会话
     * @param token
     * @param webSocketSession
     * @throws BaseException
     */
    public void addWebSocketSession(String token, WebSocketSession webSocketSession) throws BaseException {
        if (Objects.isNull(TOKEN_INFO.get(token)) ||!Boolean.TRUE.equals(TOKEN_INFO.get(token).getIsLogin()) ) {
            throw new BaseException(BaseError.UNLOGIN);
        }
        WEBSOCKET_SESSIONS.put(token, webSocketSession);
    }

    /**
     * 添加群-openvidu会话
     * @param groupUniqueId
     * @param openviduSession
     */
    public void addOpenviduSession(String groupUniqueId, Session openviduSession) {
        OPENVIDU_SESSIONS.put(groupUniqueId, openviduSession);
    }

    /**
     * 添加群-openvidu录像
     * @param groupUniqueId
     * @param recordingId
     */
    public void addOpenviduRecord(String groupUniqueId, String recordingId) {
        OPENVIDU_RECORDINGS.put(groupUniqueId, recordingId);
    }

    /**
     * 添加用户openviduToken
     * @param token
     * @param openviduToken
     * @throws BaseException
     */
    public void addOpenviduToken(String token, String openviduToken) throws BaseException {
        if (Objects.isNull(TOKEN_INFO.get(token)) || !Boolean.TRUE.equals(TOKEN_INFO.get(token).getIsLogin())) {
            throw new BaseException(BaseError.UNLOGIN);
        }
        TOKEN_INFO.get(token).setOpenviduToken(openviduToken);
    }

    /**
     * 移除ws会话
     * @param token
     */
    public void removeWebSocketSession(String token) {
        WEBSOCKET_SESSIONS.remove(token);
    }

    /**
     * 移除群视频会话
     * @param groupUniqueId
     */
    public void removeOpenviduSession(String groupUniqueId) {
        OPENVIDU_SESSIONS.remove(groupUniqueId);
    }

    /**
     * 用户退出视频会话
     * @param token
     */
    public void removeOpenviduToken(String token) {
        TokenInfoResponse tokenInfoResponse = TOKEN_INFO.get(token);
        if (Objects.nonNull(tokenInfoResponse)) {
            tokenInfoResponse.setOpenviduToken(null);
            String groupUniqueId = tokenInfoResponse.getGroupUniqueId();
            if (StringUtils.isNotBlank(groupUniqueId)) {
                if (!GROUP_REF_MEMBER.containsKey(groupUniqueId) || GROUP_REF_MEMBER.get(groupUniqueId).isEmpty()) {
                    removeOpenviduSession(groupUniqueId);
                }
            }
        }
    }


    /**
     * 添加群和用户token关联
     * @param groupUniqueId
     * @param token
     */
    public void addGroupMember(String groupUniqueId, String token) throws BaseException {
        if (Objects.isNull(TOKEN_INFO.get(token)) || !Boolean.TRUE.equals(TOKEN_INFO.get(token).getIsLogin())) {
            throw new BaseException(BaseError.UNLOGIN);
        }
        TOKEN_INFO.get(token).setGroupUniqueId(groupUniqueId);
        if (!GROUP_REF_MEMBER.containsKey(groupUniqueId)) {
            GROUP_REF_MEMBER.put(groupUniqueId, new CopyOnWriteArrayList<>());
        }
        GROUP_REF_MEMBER.get(groupUniqueId).add(token);
    }

    public void removeToken(String token) {
        TokenInfoResponse tokenInfoResponse = TOKEN_INFO.get(token);
        if (Objects.nonNull(tokenInfoResponse)) {
            String groupUniqueId = tokenInfoResponse.getGroupUniqueId();
            if (StringUtils.isNotBlank(groupUniqueId)) {
                // 将用户token移除群
                GROUP_REF_MEMBER.get(groupUniqueId).remove(token);
                removeWebSocketSession(token);
                removeOpenviduToken(token);
                // 群里没有成员时关闭群
                if (GROUP_REF_MEMBER.get(groupUniqueId).size() <= 0) {
                    GROUP_REF_MEMBER.remove(groupUniqueId);
                }
            }
        }
    }

    /**
     * 群解散
     * @param groupUniqueId
     */
    public void removeGroup(String groupUniqueId) {
        List<String> groupRefTokens = GROUP_REF_MEMBER.get(groupUniqueId);
        if (CollectionUtils.isNotEmpty(groupRefTokens)) {
            groupRefTokens.forEach(token -> {
                TokenInfoResponse tokenInfoResponse = TOKEN_INFO.get(token);
                if (Objects.nonNull(tokenInfoResponse)) {
                    // 清理用于关联该群
                    tokenInfoResponse.setGroupUniqueId(null);
                }
            });
        }
        GROUP_REF_MEMBER.remove(groupUniqueId);
    }

}
